Imports System.Collections.Generic
Imports System.Text
Imports System.Windows.Forms
Imports System.Drawing
Imports System.Data
Imports System.ComponentModel

Namespace DgvFilterPopup

	''' <summary>
	''' The main class involved in adding filtering capabilities to a DataGridView.  
	''' </summary>
	''' <remarks>
	''' This is the class that you use to add filtering capabilities to a <b>DataGridView</b>. The
	''' <b>DataGridView</b> must be data bound to a <b>DataTable</b>, a <b>DataView</b> or a <b>BindingSource</b> which in turn is
	''' bound to one of these two.
	''' When you assign a <b>DataGridView</b> to a <b>DgvFilterManager</b>, it attaches some handlers to respond 
	''' to right click on column headers and to perform some custom painting on the grid. 
	''' When the user right clicks a column header, the <b>DgvFilterManager</b> shows a popup near the column.
	''' This popup is a control that serves as host for other controls, one for each column. Only one of
	''' these child controls is visibile, based on clicked column. 
	''' We have one <i>filter host</i> control and many <i>column filter</i> child controls. 
	''' <para>
	''' The <i>filter host</i> control must be a derivation of the <see cref="DgvBaseFilterHost"/> class, while filter controls must be
	''' derived by the <see cref="DgvBaseColumnFilter"/> class. These two classes don't provide any user interface. 
	''' As a default, <b>DgvFilterManager</b> uses the standard derivation <b>DgvFilterHost</b> and, depending on column type and data type,
	''' one of the standard derivations: <see cref="DgvTextBoxColumnFilter"/>
	''' , <see cref="DgvCheckBoxColumnFilter"/>, <see cref="DgvComboBoxColumnFilter"/> 
	''' and <see cref="DgvDateColumnFilter"/>. 
	''' </para>
	''' <para>
	''' When a <b>DataGridView</b> is attached, the manager perform the following actions: 
	''' <ul>
	''' <li>it creates a <i>filter host</i>, that is an instance of the <b>DgvFilterHost</b> class. If you previously provided a
	''' <i>filter host</i>, this step is skipped.</li> 
	''' <li>it creates an array of <b>DgvBaseColumnFilter</b>, one per column, and initializes each element to a specialization 
	''' of <b>DgvBaseColumnFilter</b>. If <see cref="DgvFilterManager.AutoCreateFilters"/> is false, this step is skipped.
	''' </li>
	''' </ul>
	''' </para>
	''' <para>
	''' You can force a specific <i>column filter</i> for a certain column, intervening in this process through the events 
	''' <see cref="DgvFilterManager.ColumnFilterAdding"/> and <see cref="DgvFilterManager.ColumnFilterAdded"/>. You can also intervene, after the entire process, replacing 
	''' a <i>column filter</i> instance in the array with another instance you created. 
	''' </para>
	''' </remarks>

	Public Class DgvFilterManager

		#Region "PRIVATE FIELDS"

		Private mFilterHost As DgvBaseFilterHost
		' The host UserControl to popup
		Private mDataGridView As DataGridView
		' The DataGridView to which apply filtering
		Private mBoundDataView As DataView
		' The DataView to which the DataGridView is bound
		Private mBindingSource As BindingSource
		' The BindingSource, if any, to which the DataGridView is bound

		Private mBaseFilter As String = ""
		' Developer provided filter expression
		Private mCurrentColumnIndex As Integer = -1
		' Column Index of currently visibile filter
		Private mColumnFilterList As List(Of DgvBaseColumnFilter)
		' List of ColumnFilter objects
		Private mAutoCreateFilters As Boolean = True
		Private mFilterIsActive As Boolean = False

		#End Region


		#Region "EVENTS"


		''' <summary>
		''' Occurs when a <i>column filter</i> instance for a column is about to be automatically created.
		''' </summary>
		''' <remarks>
		''' Using this event you can set the <see cref="ColumnFilterEventArgs.ColumnFilter"/> 
		''' property to force the <see cref="DgvBaseColumnFilter"/> specialization to use for the 
		''' column. 
		''' This event is raised only if <see cref="DgvFilterManager.AutoCreateFilters"/> is true.
		''' </remarks>
		Public Event ColumnFilterAdding As ColumnFilterEventHandler


		''' <summary>
		''' Occurs when a <i>column filter</i> instance is created.
		''' This event is raised only if <see cref="DgvFilterManager.AutoCreateFilters"/> is true.
		''' </summary>
		Public Event ColumnFilterAdded As ColumnFilterEventHandler


		''' <summary>
		''' Occurs when the popup is about to be shown
		''' </summary>
		''' <remarks>
		''' Use this event to customize the popup position. Set the Handled property of the event argument to <c>true</c>.
		''' </remarks>
		Public Event PopupShowing As ColumnFilterEventHandler


		#End Region


		#Region "CONSTRUCTORS"


		''' <summary>
		''' Initializes a new instance of the <see cref="DgvFilterManager"/> class.
		''' </summary>
		Public Sub New()
		End Sub


		''' <summary>
		''' Initializes a new instance of the <see cref="DgvFilterManager"/> class.
		''' </summary>
		''' <param name="dataGridView">The <b>DataGridView</b> to which attach filtering capabilities</param>
		''' <param name="autoCreateFilters">if set to <c>true</c> automatically creates a <i>column filter</i> for each column</param>
		Public Sub New(dataGridView As DataGridView, autoCreateFilters As Boolean)
			Me.mAutoCreateFilters = autoCreateFilters
			Me.DataGridView = dataGridView
		End Sub


		''' <summary>
		''' Initializes a new instance of the <see cref="DgvFilterManager"/> class.
		''' </summary>
		''' <param name="dataGridView">The <b>DataGridView</b> to which attach filtering capabilities.</param>
		Public Sub New(dataGridView As DataGridView)
			Me.New(dataGridView, True)
		End Sub

		#End Region


		#Region "PROPERTIES"

		''' <summary>
		''' Gets or sets a value indicating whether the manager must create <i>column filters</i>.
		''' </summary>
		''' <value><c>true</c> by default.</value>
		Public Property AutoCreateFilters() As Boolean
			Get
				Return mAutoCreateFilters
			End Get
			Set
				mAutoCreateFilters = value
			End Set
		End Property



		''' <summary>
		''' Gets and sets the <i>filter host</i> to use. 
		''' </summary>
		''' <remarks>
		''' The default <i>filter host</i> is an instance of <see cref="DgvFilterHost"/>
		''' </remarks>

		Public Property FilterHost() As DgvBaseFilterHost
			Get
				If mFilterHost Is Nothing Then
					' If not provided, use the default FilterHost
                    mFilterHost = New DgvFilterHost()
                    mFilterHost.FilterManager = Me
				End If
				Return mFilterHost
			End Get
			Set
				mFilterHost = value
				' initialize FilterManager to this object
				mFilterHost.FilterManager = Me

                AddHandler mFilterHost.Popup.Closed, New ToolStripDropDownClosedEventHandler(AddressOf Popup_Closed)
			End Set
		End Property



		''' <summary>
		''' Gets and sets the DataGridView to which apply filtering capabilities.
		''' </summary>
		''' <remarks>
		''' <para>
		''' When a <b>DataGridView</b> is attached, the manager perform the following actions: 
		''' <ul>
		''' <li>it creates a <i>filter host</i>, that is an instance of the <b>DgvFilterHost</b> class. If you previously provided a
		''' <i>filter host</i>, this step is skipped.</li> 
		''' <li>it creates an array of <b>DgvBaseColumnFilter</b>, one per column, and initializes each element to a specialization 
		''' of <b>DgvBaseColumnFilter</b>. If <see cref="DgvFilterManager.AutoCreateFilters"/> is false, this step is skipped.
		''' </li>
		''' </ul>
		''' </para>
		''' <para>
		''' You can force a specific <i>column filter</i> for a certain column, intervening in this process through the events 
		''' <see cref="DgvFilterManager.ColumnFilterAdding"/> and <see cref="DgvFilterManager.ColumnFilterAdded"/>. You can also intervene, after the entire process, replacing 
		''' a <i>column filter</i> instance in the array with another instance you created. 
		''' </para>
		''' </remarks>
		Public Property DataGridView() As DataGridView
			Get
				Return mDataGridView
			End Get
			Set
				mDataGridView = value
				mColumnFilterList = New List(Of DgvBaseColumnFilter)(mDataGridView.Columns.Count)
				FindDataView()
				mDataGridView.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize
				AddHandler mDataGridView.CellMouseClick, New DataGridViewCellMouseEventHandler(AddressOf mDataGridView_CellMouseClick)
				AddHandler mDataGridView.CellPainting, New DataGridViewCellPaintingEventHandler(AddressOf mDataGridView_CellPainting)
				AddHandler mDataGridView.ColumnAdded, New DataGridViewColumnEventHandler(AddressOf mDataGridView_ColumnAdded)
				AddHandler mDataGridView.ColumnRemoved, New DataGridViewColumnEventHandler(AddressOf mDataGridView_ColumnRemoved)
				If mDataGridView Is Nothing Then
					Return
				End If
				For Each c As DataGridViewColumn In mDataGridView.Columns
					mColumnFilterList.Add(Nothing)
					CreateColumnFilter(c)
				Next
			End Set
		End Property

		''' <summary>
		''' Gets and sets developer provided filter expression. This expression
		''' will be "merged" with end-user created filters.
		''' </summary>
		''' <value>The base filter.</value>

		Public Property BaseFilter() As String
			Get
				Return mBaseFilter
			End Get
			Set
				mBaseFilter = value
				RebuildFilter()
			End Set
		End Property


		''' <summary>
		''' Gets or sets the <i>column filter</i> control related to the ColumnIndex
		''' </summary>
		''' <param name="ColumnIndex">The index of the <b>DataGridView</b> column</param>
		''' <returns>the <b>DgvBaseColumnFilter</b> related to the <b>DataGridView</b> column</returns>
		''' <remarks>
		''' This indexer allow you to get and set the <i>column filter</i> instance for the column. 
		''' You can set one of the standard <i>column filter</i> implementation or an instance 
		''' of your own <b>DgvBaseFilterColumn</b> specialization.
		''' </remarks>
		Public Default Property Item(ColumnIndex As Integer) As DgvBaseColumnFilter
			Get
				Return mColumnFilterList(ColumnIndex)
			End Get
			Set
				mColumnFilterList(ColumnIndex) = value
				value.Init(Me, FilterHost, mDataGridView.Columns(ColumnIndex), mBoundDataView)
			End Set
		End Property


		''' <summary>
		''' Gets or sets the <i>column filter</i> control related to the ColumnName
		''' </summary>
		''' <param name="ColumnName">The name of the <b>DataGridView</b> column</param>
		''' <returns>the DgvBaseColumnFilter related to the <b>DataGridView</b> column</returns>
		''' <remarks>
		''' This indexer allow you to get and set the <i>column filter</i> instance for the column. 
		''' You can set one of the standard <i>column filter</i> implementation or an instance 
		''' of your own <b>DgvBaseFilterColumn</b> specialization.
		''' </remarks>
		Public Default Property Item(ColumnName As String) As DgvBaseColumnFilter
			Get
				Return mColumnFilterList(mDataGridView.Columns(ColumnName).Index)
			End Get
			Set
				Me(mDataGridView.Columns(ColumnName).Index) = value
			End Set
		End Property



		#End Region


		#Region "DATAGRIDVIEW EVENT HANDLERS"

		Private Sub mDataGridView_ColumnRemoved(sender As Object, e As DataGridViewColumnEventArgs)
			mColumnFilterList.RemoveAt(e.Column.Index)
		End Sub

		Private Sub mDataGridView_ColumnAdded(sender As Object, e As DataGridViewColumnEventArgs)
			FindDataView()
			mColumnFilterList.Insert(e.Column.Index, Nothing)
			CreateColumnFilter(e.Column)
		End Sub


		''' <summary>
		''' Shows the popup when user right-clicks a column header
		''' </summary>
		''' <param name="sender">The event source.</param>
		''' <param name="e">The <see cref="System.Windows.Forms.DataGridViewCellMouseEventArgs"/> instance containing the event data.</param>
		Protected Overridable Sub mDataGridView_CellMouseClick(sender As Object, e As DataGridViewCellMouseEventArgs)
			If e.Button = MouseButtons.Right AndAlso e.RowIndex = -1 AndAlso e.ColumnIndex > -1 Then
				ShowPopup(e.ColumnIndex)
			End If
		End Sub

		'Based on filters state, call the appropriate protected paint helpers
		Private Sub mDataGridView_CellPainting(sender As Object, e As DataGridViewCellPaintingEventArgs)
			If e.RowIndex <> -1 Then
				Return
			End If
			'skip if it is not the header row
			'Cell Origin
			If e.RowIndex = -1 AndAlso e.ColumnIndex = -1 AndAlso mFilterIsActive Then
				OnFilteredGridPaint(sender, e)
				Return
			End If

			If FilterHost.Popup.Visible Then
				OnHighlightedColumnPaint(sender, e)
			End If

			If e.ColumnIndex = -1 Then
				Return
			End If
			If mColumnFilterList(e.ColumnIndex) IsNot Nothing AndAlso mColumnFilterList(e.ColumnIndex).Active Then
				OnFilteredColumnPaint(sender, e)
			End If
		End Sub


		''' <summary>
		''' Paints a funnel icon in the cell origin when some column is filtered.
		''' </summary>
		''' <param name="sender">The sender</param>
		''' <param name="e">The <see cref="System.Windows.Forms.DataGridViewCellPaintingEventArgs"/> instance containing the event data.</param>
		''' <remarks>
		''' Override this method to provide your own painting
		''' </remarks>
		Protected Overridable Sub OnFilteredGridPaint(sender As Object, e As DataGridViewCellPaintingEventArgs)
			e.Graphics.FillRectangle(Brushes.White, e.CellBounds)
			e.Paint(e.CellBounds, e.PaintParts And Not DataGridViewPaintParts.Background)
			Dim r As New Rectangle(e.CellBounds.X + 1, e.CellBounds.Y + 1, e.CellBounds.Width - 3, e.CellBounds.Height - 4)
			e.Graphics.DrawImage(FunnelPicture, (e.CellBounds.Width - FunnelPicture.Width) \ 2, (e.CellBounds.Height - FunnelPicture.Height) \ 2, FunnelPicture.Width, FunnelPicture.Height)
			e.Graphics.DrawRectangle(Pens.Black, r)

			e.Handled = True

			'e.Paint(e.CellBounds, DataGridViewPaintParts.All);
			'e.Graphics.DrawImage(FunnelPicture, (e.CellBounds.Width - FunnelPicture.Width) / 2, (e.CellBounds.Height - FunnelPicture.Height) / 2, FunnelPicture.Width, FunnelPicture.Height);
			'e.Handled = true;
		End Sub

		''' <summary>
		''' Performs customized column header painting when the popup is visibile. 
		''' </summary>
		''' <param name="sender">The sender.</param>
		''' <param name="e">The <see cref="System.Windows.Forms.DataGridViewCellPaintingEventArgs"/> instance containing the event data.</param>
		''' <remarks>
		''' Override this method to provide your own painting
		''' </remarks>
		Protected Overridable Sub OnHighlightedColumnPaint(sender As Object, e As DataGridViewCellPaintingEventArgs)
			If e.ColumnIndex <> mCurrentColumnIndex OrElse e.RowIndex <> -1 Then
				Return
			End If
			e.Paint(e.CellBounds, DataGridViewPaintParts.All)
			Dim r As New Rectangle(e.CellBounds.X + 1, e.CellBounds.Y + 1, e.CellBounds.Width - 3, e.CellBounds.Height - 4)
			e.Graphics.DrawRectangle(Pens.Yellow, r)
			e.Handled = True
		End Sub

		''' <summary>
		''' Performs customized column header painting when the column is filtered.
		''' </summary>
		''' <param name="sender">The sender.</param>
		''' <param name="e">The <see cref="System.Windows.Forms.DataGridViewCellPaintingEventArgs"/> instance containing the event data.</param>
		''' <remarks>
		''' Override this method to provide your own painting
		''' </remarks>
		Protected Overridable Sub OnFilteredColumnPaint(sender As Object, e As DataGridViewCellPaintingEventArgs)
			e.Graphics.FillRectangle(Brushes.White, e.CellBounds)
			e.Paint(e.CellBounds, e.PaintParts And Not DataGridViewPaintParts.Background)
			Dim r As New Rectangle(e.CellBounds.X + 1, e.CellBounds.Y + 1, e.CellBounds.Width - 3, e.CellBounds.Height - 4)
			e.Graphics.DrawRectangle(Pens.Black, r)
			e.Handled = True

		End Sub

		#End Region


		#Region "FILTERHOST MANAGING"

		'Forces column header repaint when popup is closed, cleaning customized painting performed by OnHighlightedColumnPaint
		Private Sub Popup_Closed(sender As Object, e As ToolStripDropDownClosedEventArgs)
			mDataGridView.InvalidateCell(mCurrentColumnIndex, -1)
			' Force header repaint (to hide the selection yellow frame)
		End Sub


		''' <summary>
		''' Shows the popup.
		''' </summary>
		''' <param name="ColumnIndex">Index of the column.</param>
		Public Sub ShowPopup(ColumnIndex As Integer)
			If mColumnFilterList(ColumnIndex) Is Nothing Then
				Return
			End If
			' non-data column
			Dim OldColumnIndex As Integer = mCurrentColumnIndex
			mCurrentColumnIndex = ColumnIndex
			Dim r As Rectangle = mDataGridView.GetCellDisplayRectangle(ColumnIndex, -1, False)
			' get the header size info
			FilterHost.CurrentColumnFilter = mColumnFilterList(ColumnIndex)
			Try
				'use "try" because old column could have been removed
				mDataGridView.InvalidateCell(OldColumnIndex, -1)
			Catch
			End Try
			Dim e As New ColumnFilterEventArgs(mDataGridView.Columns(ColumnIndex), mColumnFilterList(ColumnIndex))
			RaiseEvent PopupShowing(Me, e)
			If Not e.Handled Then
				FilterHost.Popup.Show(mDataGridView, r.X + r.Width - 4, r.Y - 10)
			End If
			' show the filterhost popup near the column
			FilterHost.Popup.Focus()

			mDataGridView.InvalidateCell(mCurrentColumnIndex, -1)
			' Force header repaint (to show a selection yellow frame)
		End Sub

		#End Region


		#Region "COLUMN FILTERS MANAGING"


		''' <summary>
		''' Activates / Deactivates the filter for the column specified by ColumnIndex.
		''' </summary>
		''' <param name="Active">The active state to set</param>
		''' <param name="ColumnIndex">Index of the column.</param>
		Public Sub ActivateFilter(Active As Boolean, ColumnIndex As Integer)
			Me(ColumnIndex).Active = Active
			RebuildFilter()
		End Sub



		''' <summary>
		''' Activates / Deactivates the filter for the column specified by ColumnName.
		''' </summary>
		''' <param name="Active">The active state to set</param>
		''' <param name="ColumnName">Name of the column.</param>
		Public Sub ActivateFilter(Active As Boolean, ColumnName As String)
			Me(ColumnName).Active = Active
			RebuildFilter()
		End Sub


		''' <summary>
		''' Activates / Deactivates the filter for the current, that is last right-clicked, column.
		''' </summary>
		''' <param name="Active">The active state to set</param>
		Public Sub ActivateFilter(Active As Boolean)
			If mCurrentColumnIndex = -1 Then
				Return
			End If
			Me(mCurrentColumnIndex).Active = Active
			If Active Then
				Me(mCurrentColumnIndex).FilterExpressionBuild()
			End If
			RebuildFilter()
		End Sub



		''' <summary>
		''' Activates / Deactivates all filters.
		''' </summary>
		''' <param name="Active">The active state to set</param>
		Public Sub ActivateAllFilters(Active As Boolean)
			For Each CF As DgvBaseColumnFilter In mColumnFilterList
				If CF Is Nothing Then
					Continue For
				End If
				CF.Active = Active
				If Active Then
					CF.FilterExpressionBuild()
				End If
			Next
			RebuildFilter()
		End Sub



		''' <summary>
		''' Rebuilds the whole filter expression.
		''' </summary>
		''' <remarks>
		''' The whole filter expression is the conjunction of each <i>column filter</i> and the <see cref="BaseFilter"/>. 
		''' Call this method to refresh and apply the whole filter expression.
		''' </remarks>
		Public Sub RebuildFilter()
			mFilterIsActive = False
			Dim Filter As String = ""
			For Each CF As DgvBaseColumnFilter In mColumnFilterList
				If CF Is Nothing Then
					Continue For
				End If
				If CF.Active AndAlso CF.FilterExpression <> "" Then
					Filter += " AND (" + CF.FilterExpression & ")"
					CF.DataGridViewColumn.HeaderText = CF.FilterCaption
				Else
					CF.DataGridViewColumn.HeaderText = CF.OriginalDataGridViewColumnHeaderText

				End If
			Next
			If Filter <> "" Then
				mFilterIsActive = True
				Filter = If((mBaseFilter = ""), "1=1 " & Filter, mBaseFilter & " " & Filter)
			Else
				Filter = mBaseFilter
			End If

			' Apply the filter only if any changes occurred
			Try
				If mBindingSource IsNot Nothing Then
					If mBindingSource.Filter <> Filter Then
						mBindingSource.Filter = Filter
					End If
				Else
					If mBoundDataView.RowFilter <> Filter Then
						mBoundDataView.RowFilter = Filter
					End If
				End If
			Catch
				Console.WriteLine("Invalid filter: " & Filter)
			End Try

		End Sub


		#End Region


		#Region "HELPERS"

		' Checks if the DataGridView is data bound and the data source finally resolves to a DataView.
		Private Sub FindDataView()
			mBindingSource = Nothing
			Dim DataSource As Object = mDataGridView.DataSource
			Dim DataMember As String = mDataGridView.DataMember

			Dim ExceptionMsg As String = "DataGridViewFilter can only work with bound DataGridView. The DataSource must be a DataSet, a DataTable, a DataView or a BindingSource which is bound to a DataSet, a DataTable or a DataView "

			While Not (TypeOf DataSource Is DataView)

				If DataSource Is Nothing Then
					Return
				End If

				If TypeOf DataSource Is BindingSource Then
					mBindingSource = DirectCast(DataSource, BindingSource)
					DataMember = DirectCast(DataSource, BindingSource).DataMember
					DataSource = DirectCast(DataSource, BindingSource).DataSource
					Continue While
				End If
				If TypeOf DataSource Is DataSet Then
					DataSource = DirectCast(DataSource, DataSet).Tables(DataMember)
					DataMember = ""
					Continue While
				End If
				If TypeOf DataSource Is DataTable Then
					DataSource = DirectCast(DataSource, DataTable).DefaultView
					Exit While
				End If
				'other types are not allowed
				Throw New Exception(ExceptionMsg)
			End While
			mBoundDataView = DirectCast(DataSource, DataView)
		End Sub


		'The funnel picture
        Private Shared mFilterPicture As Drawing.Image


		''' <summary>
		''' Gets a funnel picture.
		''' </summary>
        Public Shared ReadOnly Property FunnelPicture() As Drawing.Image
            Get
                If mFilterPicture Is Nothing Then
                    Dim resources As New System.ComponentModel.ComponentResourceManager(GetType(DgvFilterHost))
                    mFilterPicture = DirectCast(resources.GetObject("pictureBox1.Image"), System.Drawing.Image)
                End If
                Return mFilterPicture
            End Get
        End Property


		Private Sub CreateColumnFilter(c As DataGridViewColumn)
			If Not mAutoCreateFilters Then
				Return
			End If
			'Raise the event about column filter creation
			Dim e As New ColumnFilterEventArgs(c, Nothing)
			RaiseEvent ColumnFilterAdding(Me, e)
			'if not provided, by an event handler, proceed with standard filter creation
			If e.ColumnFilter Is Nothing Then
				Dim DataType As Type = Nothing
				If c.DataPropertyName <> "" Then
					DataType = mBoundDataView.Table.Columns(c.DataPropertyName).DataType

					Select Case c.[GetType]().Name
						Case "DataGridViewComboBoxColumn"
							e.ColumnFilter = New DgvComboBoxColumnFilter()
							Exit Select
						Case "DataGridViewCheckBoxColumn"
							e.ColumnFilter = New DgvCheckBoxColumnFilter()
							Exit Select
						Case "DataGridViewTextBoxColumn"
							If DataType Is GetType(DateTime) Then
								e.ColumnFilter = New DgvDateColumnFilter()
							Else
								e.ColumnFilter = New DgvTextBoxColumnFilter()
							End If
							Exit Select
					End Select
				End If
			End If
			mColumnFilterList(c.Index) = e.ColumnFilter
			If e.ColumnFilter IsNot Nothing Then
				' == null when non-data column
				RaiseEvent ColumnFilterAdded(Me, e)
				e.ColumnFilter.Init(Me, FilterHost, c, mBoundDataView)
			End If
		End Sub

		#End Region



	End Class
End Namespace
